-module(state_storage).
-include("definitions.hrl").

-export([start/1, stop/0, updateState/1, flush/0, init/0, getCurrentStates/0, getLastForDevice/1]).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                   интерфейсные
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
start(_) ->%Pid
  true = register(stateStorage, spawn(state_storage, init, [])).

init() ->
  Tab = ets:new(stateTable, [named_table, {keypos, #stateRecord.deviceId}]),
  loopEvent(Tab, 0)
.



updateState(State) ->
  case whereis(stateStorage) of
    undefined -> ok;
    Pid -> Pid ! {update, State, self()}
  end.

getCurrentStates() ->
  case whereis(stateStorage) of
    undefined ->
      io:format("stateStorage finished~n"),
      ok;
    Pid -> Pid ! {getCurrentState, self()},
      receive
        States when is_list(States) ->
          States
      end
  end.

getLastForDevice(DeviceId) ->
  case whereis(stateStorage) of
    undefined ->
      io:format("stateStorage finished~n"),
      ok;
    Pid -> Pid ! {getLastState, DeviceId, self()},
      receive
        {last, State} ->
          State
      end
  end
.

stop() ->
  io:format("stateStorage finished~n"),
  stateStorage ! stop.

%неблокирующая
% а стала блокирующая
flush() ->
  stateStorage ! {flush, self()},
  receive
    {ok, flushed} -> ok
  end.

loopEvent(Tab, UnsavedCount) ->
  receive
    stop ->
      flushToMnesia(),
      ok;

    {flush, Pid} ->
      ok = flushToMnesia(),
      Pid ! {ok, flushed},
      loopEvent(Tab, 0);

    {update, State, _} ->%From
      ets:insert(stateTable, State),
      if
        UnsavedCount > ?BUFFER_SIZE ->
          ok = flushToMnesia(),
          loopEvent(Tab, 0);
        true ->
          loopEvent(Tab, UnsavedCount + 1)
      end;

    {getCurrentState, From} ->
      States = getAll(),
      From ! States,
      loopEvent(Tab, UnsavedCount);

    {getLastState, DeviceId, Pid} when is_pid(Pid), is_integer(DeviceId) ->
      getLastState(DeviceId, Pid),
      loopEvent(Tab, UnsavedCount)
  end.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                   реализация
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

flushToMnesia() ->
  States = getAll(),
  flushItems(States).

flushItems([]) ->
  %ets:delete_all_objects(stateTable),
  ok;
flushItems([State | States]) ->
  test_storage:updateState(State),
  flushItems(States)
.

getAll() ->
  lists:flatten(ets:match(stateTable, '$1')).

getLastState(DeviceId, Pid) ->
  State = ets:lookup(stateTable, DeviceId),
  Result = case State of
             [] ->
               error("state_storage: getLastState: State was not restored after fall");
             List when is_list(List) -> hd(List);
             Otherwise -> Otherwise
           end,
  Pid ! {last, Result}.